﻿using System.Diagnostics;
using System.Threading;

namespace Zo.Queues
{
    /// <summary>
    /// 单线程安全队列。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    [DebuggerDisplay("Count={" + nameof(Count) + "}")]
    public sealed class MonoConcurrentQueue<T> : MonoConcurrentQueueBase<T>
    {
        /// <summary>
        /// 入队。
        /// </summary>
        /// <param name="item">元素。</param>
        public override void Enqueue(T item)
        {
            // 创建节点。
            var node = new Node { Value = item };

            // 定义旧的末节点。
            Node oldTail = null;

            // 定义旧的下一个节点。

            var update = false;

            // 是否已更新。
            while (!update)
            {
                oldTail = _tail;
                var oldNext = oldTail.Next;

                // 是否已经更新了末节点。
                if (_tail == oldTail)
                {
                    if (oldNext == null)
                    {
                        // 将新节点增加到集合的末尾。
                        update = Interlocked.CompareExchange(ref _tail.Next, node, null) == null;
                    }
                    else
                    {
                        Interlocked.CompareExchange(ref _tail, oldNext, oldTail);
                    }
                }
            }
            // 更新末节点信息。
            Interlocked.CompareExchange(ref _tail, node, oldTail);

            //更新元素的总个数。
            Interlocked.Increment(ref _count);
        }

        /// <summary>
        /// 出队。
        /// </summary>
        /// <returns>元素。</returns>
        public override T Dequeue()
        {
            T result;

            var status = TryDequeue(out result);

            return status ? result : default(T);
        }

        /// <summary>
        /// 出队。
        /// </summary>
        /// <param name="result">元素。</param>
        /// <returns>是否成功。</returns>
        public override bool TryDequeue(out T result)
        {
            result = default(T);
            Node oldNext = null;
            var advanced = false;

            while (!advanced)
            {
                var oldHead = _head;
                var oldTail = _tail;
                oldNext = oldHead.Next;

                if (oldHead == _head)
                {
                    // Empty case ?
                    if (oldHead == oldTail)
                    {
                        // This should be false then
                        if (oldNext != null)
                        {
                            // If not then the linked list is mal formed, update tail
                            Interlocked.CompareExchange(ref _tail, oldNext, oldTail);
                            continue;
                        }
                        result = default(T);
                        return false;
                    }
                    else
                    {
                        result = oldNext.Value;

                        // 将当前集合中的首节点移除。
                        advanced = Interlocked.CompareExchange(ref _head, oldNext, oldHead) == oldHead;
                    }
                }
            }

            oldNext.Value = default(T);

            //更新元素的总个数。
            Interlocked.Decrement(ref _count);

            return true;
        }

        /// <summary>
        /// 清空。
        /// </summary>
        internal void Clear()
        {
            _count = 0;
            _tail = _head = new Node();
        }
    }
}